package com.to8to.autotask.resulthandler;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

import org.elasticsearch.common.collect.Lists;
import org.elasticsearch.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.to8to.autotask.allocate.ecommercer.AllocateEcommercerTask;
import com.to8to.autotask.countdown.CountDownTask;
import com.to8to.autotask.deduction.ForfeitDeductTask;
import com.to8to.autotask.deduction.PollingFeeDeductTask;
import com.to8to.autotask.gcjd.SetKGDJTask;
import com.to8to.autotask.rpc.CallClient;
import com.to8to.autotask.scheduler.AutoTaskScheduler;
import com.to8to.autotask.util.Utils;
import com.to8to.autotask.zbinfo.UpdateZBInfoTask;
import com.to8to.es.util.LogUtil;
import com.to8to.thrift.sms.SMSService;
import com.to8to.thrift.sms.SendMsgRequest;
import com.to8to.thrift.sms.TTarget;

/**
 * FailHandler.java
 * 作 者：atom.liu
 * 版 本：v2.0
 * 日 期：2014年12月15日
 * 描 述：自动任务异常处理。 
 */
public class FailHandler
{
    private static Logger logger = LoggerFactory.getLogger(FailHandler.class);

    /**
     * 任务执行次数映射。 Map<任务名，Map<日期，执行次数>>
     */
    private static Map<String, Map<String, Integer>> taskCountMap = Maps.newHashMap();

    /**
     * 失败通知邮件列表
     */
    private static CopyOnWriteArrayList<String> noticeEmailList = Lists.newCopyOnWriteArrayList();

    static
    {
        //分配审核客服、装后客服会每天执行多次，如果一次失败，则不再处理。其余的一天执行一次，如果sql失败，则需要再次处理。
        taskCountMap.put(AllocateEcommercerTask.class.getSimpleName(), Maps.newHashMap());
        taskCountMap.put(CountDownTask.class.getSimpleName(), Maps.newHashMap());
        taskCountMap.put(ForfeitDeductTask.class.getSimpleName(), Maps.newHashMap());
        taskCountMap.put(PollingFeeDeductTask.class.getSimpleName(), Maps.newHashMap());
        taskCountMap.put(SetKGDJTask.class.getSimpleName(), Maps.newHashMap());
        taskCountMap.put(UpdateZBInfoTask.class.getSimpleName(), Maps.newHashMap());
    }

    /**
     * 失败处理
     */
    public static void handler(Class<? extends Runnable> clazz)
    {
        String className = clazz.getSimpleName();
        Map<String, Integer> countMap = taskCountMap.get(className);
        if (countMap == null)
        {
            logger.error(String.format("任务[ %s ]没有提供异常处理！", className));
            return;
        }

        String today = Utils.getTodayStr();
        Integer count = countMap.get(today) == null ? 0 : countMap.get(today);
        if (count >= 2)
        {
            logger.info(String.format("任务[ %s ]失败重试次数已经超过2次，将邮件通知开发人员，不再处理！", className));
            notice(className);
            return;
        }

        try
        {
            logger.info(String.format("任务[ %s ]将在一个小时之后将会再次执行", className));
            Runnable task = clazz.newInstance();
            AutoTaskScheduler.executeAfterNHour(task, 1);
            count = count + 1;
            countMap.put(today, count);
        }
        catch (Throwable e)
        {
            logger.error("生成任务实例失败(clazz.newInstance方法)！{} \n {}", e, LogUtil.logStackTrace(e));
        }
    }

    /**
     * 通知 
     */
    public static void notice(String taskName)
    {
        if (Utils.isNullOrEmpty(noticeEmailList))
        {
            logger.info("没有配置Email，将不会通知！如需配置，请在节点中心task.properties中进行设置");
            return;
        }

        SMSService.Iface service = CallClient.getInstance().getSMSService();
        List<TTarget> targetList = Lists.newArrayList();
        for (String email : noticeEmailList)
        {
            TTarget tt = new TTarget();
            tt.setSend_type(2);
            tt.setContact(email);
            targetList.add(tt);
        }
        SendMsgRequest req = new SendMsgRequest();
        req.setTitle("自动任务执行失败");
        req.setContent(String.format("CRM-自动任务[ %s ] 执行失败，请查明原因！", taskName));
        req.setTargets(targetList);
        try
        {
            service.sendMsg(req);
        }
        catch (Throwable e)
        {
            logger.error("调用SMSService服务发送邮件失败！{} \n {}", e, LogUtil.logStackTrace(e));
        }
    }

    /**
     * 初始化通知email 
     */
    public static void initNoticeEmail(String[] noticeEmails)
    {
        noticeEmailList.clear();
        if (noticeEmails == null || noticeEmails.length < 0)
            return;
        noticeEmailList.addAll(Arrays.asList(noticeEmails));
        logger.info("自动任务失败通知Eaml：" + noticeEmailList);
    }
}
